/*****************************************************************************************/
/**	INITIALIZATION																		**/
/*****************************************************************************************/

/* Constants */
CTRL_STATE_OUT							= 1
CTRL_STATE_IN							= 2
CTRL_STATE_DOWN							= 3

/* Table */
BelControls								= {}

/* Initialization */
BelControls.Register					= function( ctrl, dermaType, ... )

	/* Variables */
	local outColor						= Color( 175, 175, 175, 200 )
	local inColor						= Color( 104, 175, 252, 200 )
	local downColor						= Color( 125, 125, 125, 200 )
	local textColor						= Color( 255, 255, 255, 200 )
	local xPos,yPos						= ctrl:GetPos()
	
	/* Faders */
	ctrl.BackgroundFader				= Fader(
		Keyframe( 0, outColor ),
		Keyframe( 0.5, inColor ),
		Keyframe( 1, downColor ),
		0.4,
		0.25
	)
	ctrl.BackgroundFader.OnFadeComplete	= BelControls.BackgroundFadeComplete
	ctrl.ShowHideFader					= Fader(
		Keyframe( 0, { Width=0, Height=8, Alpha=0 } ),
		Keyframe( 0.5, { Width=ctrl:GetWide(), Height=8, Alpha=127 } ),
		Keyframe( 1, { Width=ctrl:GetWide(), Height=ctrl:GetTall(), Alpha=255 } ),
		3,
		1.5
	)
	ctrl.ShowHideFader.OnFadeComplete	= BelControls.ShowHideFadeComplete
	
	/* General design */
	ctrl.SplitDesign					= true
	ctrl.IncrustBorder					= true
	ctrl.CornerSizeRatio				= 0.05
	ctrl.CurrentControlState			= CTRL_STATE_OUT
	ctrl.DropShadow						= false
	ctrl.ShadowColor					= Color( 10, 10, 10, 200 )
	ctrl.Origin							= { x=0.5, y=0.5 }
	ctrl.FinalPosition					= { x=xPos, y=yPos }
	ctrl.WaitForChildren				= true
	ctrl.Margin							= { l=8, r=8, t=8, b=8 }
	ctrl.Padding						= { l=16, r=16, t=16, b=16 }
	
	/* Internal */
	ctrl.TextColor						= Color( 255, 255, 255, 255 )
	ctrl.TextColorHovered				= true
	
	/* Derma class */
	ctrl.DermaType						= dermaType
	
	/* Pre-actions */
	if ctrl.SetSize then ctrl:SetSize( 0, 0 ) end
	if ctrl.SetVisible then ctrl:SetVisible( true ) end
	
	/* Initialization done */
	ctrl.IsRegistered					= true
	
	/* Non-hookable functions */
	ctrl.SetBackgroundColors			= BelControls.SetBackgroundColors
	ctrl.AddChild						= BelControls.AddChild
	
	/* Hooks list */
	BelControls.Hooks["is_a"][ctrl]					= {}
	BelControls.Hooks["GetCurrentBackcolor"][ctrl]	= {}
	BelControls.Hooks["GetFinalPos"][ctrl]			= {}
	BelControls.Hooks["SetFinalPos"][ctrl]			= {}
	BelControls.Hooks["GetTextColor"][ctrl]			= {}
	BelControls.Hooks["SetTextColor"][ctrl]			= {}
	BelControls.Hooks["GetTextColorHovered"][ctrl]	= {}
	BelControls.Hooks["SetTextColorHovered"][ctrl]	= {}
	BelControls.Hooks["SetMaxWide"][ctrl]			= {}
	BelControls.Hooks["SetMaxTall"][ctrl]			= {}
	BelControls.Hooks["GetMaxWide"][ctrl]			= {}
	BelControls.Hooks["GetMaxTall"][ctrl]			= {}
	BelControls.Hooks["GetMaxAlpha"][ctrl]			= {}
	BelControls.Hooks["SetMaxAlpha"][ctrl]			= {}
	BelControls.Hooks["IsVisible"][ctrl]			= {}
	BelControls.Hooks["SetVisible"][ctrl]			= {}
	BelControls.Hooks["OnCursorEntered"][ctrl]		= {}
	BelControls.Hooks["OnCursorExited"][ctrl]		= {}
	BelControls.Hooks["OnMousePressed"][ctrl]		= {}
	BelControls.Hooks["OnMouseReleased"][ctrl]		= {}
	BelControls.Hooks["Paint"][ctrl]				= {}
	BelControls.Hooks["Draw"][ctrl]					= {}
	BelControls.Hooks["Dispose"][ctrl]				= {}
	BelControls.Hooks["OnShown"][ctrl]				= {}
	BelControls.Hooks["OnHidden"][ctrl]				= {}
	BelControls.Hooks["ChildShown"][ctrl]			= {}
	BelControls.Hooks["ChildHidden"][ctrl]			= {}
	
	/* Default hooks */
	BelControls.AddHook( "is_a", ctrl, function( ctrl, class ) return BelControls.is_a( ctrl, class ) end )
	BelControls.AddHook( "GetCurrentBackcolor", ctrl, function( ctrl ) return BelControls.GetCurrentBackcolor( ctrl ) end )
	BelControls.AddHook( "GetFinalPos", ctrl, function( ctrl ) return BelControls.GetFinalPos( ctrl ) end )
	BelControls.AddHook( "SetFinalPos", ctrl, function( ctrl, x, y ) return BelControls.SetFinalPos( ctrl, x, y ) end )
	BelControls.AddHook( "GetTextColor", ctrl, function( ctrl ) return BelControls.GetTextColor( ctrl ) end )
	BelControls.AddHook( "SetTextColor", ctrl, function( ctrl, value ) return BelControls.SetTextColor( ctrl, value ) end )
	BelControls.AddHook( "GetTextColorHovered", ctrl, function( ctrl ) return BelControls.GetTextColorHovered( ctrl ) end )
	BelControls.AddHook( "SetTextColorHovered", ctrl, function( ctrl, value ) return BelControls.SetTextColorHovered( ctrl, value ) end )
	BelControls.AddHook( "SetMaxWide", ctrl, function( ctrl, value ) return BelControls.SetMaxWide( ctrl, value ) end )
	BelControls.AddHook( "SetMaxTall", ctrl, function( ctrl, value ) return BelControls.SetMaxTall( ctrl, value ) end )
	BelControls.AddHook( "GetMaxWide", ctrl, function( ctrl ) return BelControls.GetMaxWide( ctrl ) end )
	BelControls.AddHook( "GetMaxTall", ctrl, function( ctrl ) return BelControls.GetMaxTall( ctrl ) end )
	BelControls.AddHook( "GetMaxAlpha", ctrl, function( ctrl, value ) return BelControls.GetMaxAlpha( ctrl, value ) end )
	BelControls.AddHook( "SetMaxAlpha", ctrl, function( ctrl, value ) return BelControls.SetMaxAlpha( ctrl, value ) end )
	BelControls.AddHook( "IsVisible", ctrl, function( ctrl ) return BelControls.IsVisible( ctrl ) end )
	BelControls.AddHook( "SetVisible", ctrl, function( ctrl, value ) return BelControls.SetVisible( ctrl, value ) end )
	BelControls.AddHook( "OnCursorEntered", ctrl, function( ctrl ) return BelControls.OnCursorEntered( ctrl ) end )
	BelControls.AddHook( "OnCursorExited", ctrl, function( ctrl ) return BelControls.OnCursorExited( ctrl ) end )
	BelControls.AddHook( "OnMousePressed", ctrl, function( ctrl ) return BelControls.OnMousePressed( ctrl ) end )
	BelControls.AddHook( "OnMouseReleased", ctrl, function( ctrl ) return BelControls.OnMouseReleased( ctrl ) end )
	BelControls.AddHook( "Paint", ctrl, function( ctrl ) return BelControls.Paint( ctrl ) end )
	BelControls.AddHook( "Draw", ctrl, function( ctrl, color ) return BelControls.Draw( ctrl, color ) end )
	BelControls.AddHook( "Dispose", ctrl, function( ctrl ) return BelControls.Dispose( ctrl ) end )
	BelControls.AddHook( "ChildShown", ctrl, function( ctrl, child ) return BelControls.ChildShown( child ) end )
	BelControls.AddHook( "ChildHidden", ctrl, function( ctrl, child ) return BelControls.ChildHidden( child ) end )
	
	/* Call functions */
	ctrl.is_a							= function( self, class ) return BelControls.Call( self, "is_a", class ) end
	ctrl.GetCurrentBackcolor			= function( self ) return BelControls.Call( self, "GetCurrentBackcolor" ) end
	ctrl.GetFinalPos					= function( self ) return BelControls.Call( self, "GetFinalPos" ) end
	ctrl.SetFinalPos					= function( self, x, y ) return BelControls.Call( self, "SetFinalPos", x, y ) end
	ctrl.GetTextColor					= function( self ) return BelControls.Call( self, "GetTextColor" ) end
	ctrl.SetTextColor					= function( self, value ) return BelControls.Call( self, "SetTextColor", value ) end
	ctrl.GetTextColorHovered			= function( self ) return BelControls.Call( self, "GetTextColorHovered" ) end
	ctrl.SetTextColorHovered			= function( self, value ) return BelControls.Call( self, "SetTextColorHovered", value ) end
	ctrl.SetMaxWide						= function( self, value ) return BelControls.Call( self, "SetMaxWide", value ) end
	ctrl.SetMaxTall						= function( self, value ) return BelControls.Call( self, "SetMaxTall", value ) end
	ctrl.GetMaxWide						= function( self ) return BelControls.Call( self, "GetMaxWide" ) end
	ctrl.GetMaxTall						= function( self ) return BelControls.Call( self, "GetMaxTall" ) end
	ctrl.GetMaxAlpha					= function( self, value ) return BelControls.Call( self, "GetMaxAlpha", value ) end
	ctrl.SetMaxAlpha					= function( self, value ) return BelControls.Call( self, "SetMaxAlpha", value ) end
	ctrl.IsVisible						= function( self ) return BelControls.Call( self, "IsVisible" ) end
	ctrl.SetVisible						= function( self, value ) return BelControls.Call( self, "SetVisible", value ) end
	ctrl.OnCursorEntered				= function( self ) return BelControls.Call( self, "OnCursorEntered" ) end
	ctrl.OnCursorExited					= function( self ) return BelControls.Call( self, "OnCursorExited" ) end
	ctrl.OnMousePressed					= function( self ) return BelControls.Call( self, "OnMousePressed" ) end
	ctrl.OnMouseReleased				= function( self ) return BelControls.Call( self, "OnMouseReleased" ) end
	ctrl.Paint							= function( self ) return BelControls.Call( self, "Paint" ) end
	ctrl.Draw							= function( self, color ) return BelControls.Call( self, "Draw", color ) end
	ctrl.Dispose						= function( self ) return BelControls.Call( self, "Dispose" ) end
	ctrl.OnShown						= function( self ) return BelControls.Call( self, "OnShown", self ) end
	ctrl.OnHidden						= function( self ) return BelControls.Call( self, "OnHidden", self ) end
	ctrl.ChildShown						= function( self, child ) return BelControls.Call( self, "ChildShown", child ) end
	ctrl.ChildHidden					= function( self, child ) return BelControls.Call( self, "ChildHidden", child ) end
	
	/* Fader hooks */
	ctrl.BackgroundFader.LinkedObject	= ctrl
	ctrl.BackgroundFader.OnFading		= BelControls.BackgroundFaderTick
	ctrl.ShowHideFader.LinkedObject		= ctrl
	ctrl.ShowHideFader.OnFading			= BelControls.ShowHideFaderTick
	
	/* Register child to parent */
	ctrl.Children						= {}
	if IsPanel( ctrl:GetParent() ) then
	
		/* Parent needs to be a '<Bel...>' control */
		if not ctrl:GetParent().IsRegistered then
			 if zed then zed = zed end -- DEBUG:Msg( "Parent is not a BELmod control or is not registered yet, cannot link.", "BelControls.Register" )
			
		/* Insert into parent's children list */
		else
			BelControls.AddChild( ctrl:GetParent(), ctrl )
		end
	end
end

/*****************************************************************************************/
/**	NON-HOOKABLE FUNCTIONS																**/
/*****************************************************************************************/

/* Add a child to a control */
BelControls.AddChild					= function( parent, child )
	
	/* Only if the parent doesn't have that child yet */
	if not parent.Children[child] then
	
		/* Insert it */
		table.insert( parent.Children, child )
		
		/* Debug output */
		 if zed then zed = zed end -- DEBUG:Msg( "Child added.", "BelControls.AddChild" )
		
		/* Register hooks */
		BelControls.AddHook( "OnShown", child, parent.ChildShown )
		BelControls.AddHook( "OnHidden", child, parent.ChildHidden )
	else
		/* Debug output */
		 if zed then zed = zed end -- DEBUG:Msg( "Child already present.", "BelControls.AddChild" )
	end
end

/* Set background colors */
BelControls.SetBackgroundColors			= function( ctrl, ... )

	/* Variables */
	local color							= select( 1, ... )
	local i								= 1
	
	/* Loop arguments */
	while color do
	
		/* If we reached the keyframes count, stop */
		if i > table.Count( ctrl.BackgroundFader.Animation.Keyframes ) then
			break
		end
	
		/* Only if argument is a color */
		if IsColor( color ) then
			
			/* Change the keyframe color */
			ctrl.BackgroundFader.Animation.Keyframes[i].Value = color
		end
		
		/* Get the next argument */
		i								= i + 1
		color							= select( i, ... )
	end
end

/*****************************************************************************************/
/**	HOOKABLE FUNCTIONS																	**/
/*****************************************************************************************/

/* Class check */
BelControls.is_a						= function( ctrl, class )

	/* Check class */
	return
		class == BelButton or
		class == "BelButton" or
		class == ctrl.BaseClass or
		class == ctrl:GetClassName() or
		class == ctrl.DermaType or
		class == ctrl.DermaType.Derma.ClassName or
		class == ctrl.DermaType.Derma.BaseClass
end

/* Get control position when fully shown */
BelControls.GetFinalPos					= function( ctrl )
	return ctrl.FinalPosition
end

/* Set control position when fully shown */
BelControls.SetFinalPos					= function( ctrl, xPos, yPos )
	
	/* Ensure valid numbers */
	if not IsNumber( xPos ) or not IsNumber( yPos ) then
		DEBUG:ErrMsg( "X and Y must be valid numbers.", "BelControls.SetFinalPos" )
		return
	end
	
	/* Set position */
	ctrl.FinalPosition					= { x=xPos, y=yPos }
end

/* Get control text color */
BelControls.GetTextColor				= function( ctrl )
	if ctrl.DermaType.GetTextColor then
		return ctrl.DermaType.GetTextColor( ctrl )
	else
		return ctrl.TextColor
	end
end

/* Set control text color */
BelControls.SetTextColor				= function( ctrl, value )
	if ctrl.DermaType.SetTextColor then
		ctrl.DermaType.SetTextColor( ctrl, value )
	elseif IsColor( value ) then
		ctrl.TextColor					= value
	end
end

/* Get control text color hovered */
BelControls.GetTextColorHovered			= function( ctrl )
	if ctrl.DermaType.GetTextColorHovered then
		return ctrl.DermaType.GetTextColorHovered( ctrl )
	else
		return ctrl.TextColorHovered
	end
end

/* Set control text color hovered */
BelControls.SetTextColorHovered			= function( ctrl, value )
	if ctrl.DermaType.SetTextColorHovered then
		ctrl.DermaType.SetTextColorHovered( ctrl, value )
	elseif IsColor( value ) then
		ctrl.TextColorHovered			= value
	end
end

/* Gets the max width of control */
BelControls.GetMaxWide					= function( ctrl )
	return ctrl.ShowHideFader.Animation.Keyframes[3].Value.Width
end

/* Set max width of control */
BelControls.SetMaxWide					= function( ctrl, value )
	
	/* Ensure valid value */
	if not IsNumber( value ) or value < 0 then
		value = 0
	end
	
	/* Update show / hide fader */
	ctrl.ShowHideFader.Animation.Keyframes[2].Value.Width = value
	ctrl.ShowHideFader.Animation.Keyframes[3].Value.Width = value
end

/* Gets the max height of control */
BelControls.GetMaxTall					= function( ctrl )
	return ctrl.ShowHideFader.Animation.Keyframes[3].Value.Height
end

/* Set max height of control */
BelControls.SetMaxTall					= function( ctrl, value )
	
	/* Ensure valid value */
	if not IsNumber( value ) or value < 0 then
		value							= 0
	end
	
	/* Update show / hide fader */
	ctrl.ShowHideFader.Animation.Keyframes[3].Value.Height = value
end

/* Gets the maximum possible alpha */
BelControls.GetMaxAlpha					= function( ctrl )
	return ctrl.ShowHideFader.Animation.Keyframes[3].Value.Alpha
end

/* Set max alpha of control */
BelControls.SetMaxAlpha					= function( ctrl, value )
	
	/* Ensure valid value */
	if not IsNumber( value ) or value < 0 then
		value							= 0
	elseif value > 255 then
		value							= 255
	end
	
	/* Update show / hide fader */
	ctrl.ShowHideFader.Animation.Keyframes[3].Value.Alpha = math.Round( value / 2, 0 )
	ctrl.ShowHideFader.Animation.Keyframes[3].Value.Alpha = value
end

/* Determine if control is visible or not */
BelControls.IsVisible					= function( ctrl )
	return not ctrl.ShowHideFader:IsAtMin()
end

/* Change visible state of control */
BelControls.SetVisible					= function( ctrl, value )

	/* Convert to bool if necessary */
	value								= util.tobool( value )
	
	/* Debug output */
	if value then
		 if zed then zed = zed end -- DEBUG:Msg( "Showing control", "BelControls.SetVisible" )
	else
		 if zed then zed = zed end -- DEBUG:Msg( "Hiding control", "BelControls.SetVisible" )
	end
	
	/* If we want to show it, fade in */
	if value then
		 if zed then zed = zed end -- DEBUG:Msg( "Start of fade in", "BelControls.SetVisible" )
		ctrl.ShowHideFader:FadeIn()
		
		/* All should be shown at once */
		if not ctrl.WaitForChildren then
			for k,v in pairs( ctrl.Children ) do
				v:SetVisible( true )
			end
		end
		
	/* Otherwise fade out */
	else
		/* If control has no children then just fade it */
		if not IsTable( ctrl.Children ) or table.Count( ctrl.Children ) == 0 then
			 if zed then zed = zed end -- DEBUG:Msg( "No children, fading control. Duration: " .. tostring( ctrl.ShowHideFader.OutDuration ), "BelControls.SetVisible" )
			ctrl.ShowHideFader:FadeOut()
			
		/* If we shouldn't wait for children hide them at the same time */
		elseif not ctrl.WaitForChildren then
			for k,v in pairs( ctrl.Children ) do
				v:SetVisible( false )
			end
			ctrl.ShowHideFader:FadeOut()
			
		/* Otherwise start hiding the last child */
		else
			local count					= table.Count( ctrl.Children )
			 if zed then zed = zed end -- DEBUG:Msg( "Chilren to hide: " .. tostring( count ), "BelControls.SetVisible" )
			ctrl.Children[count]:SetVisible( false )
		end
	end
end

/* Get the current color */
BelControls.GetCurrentBackcolor			= function( ctrl )
	
	/* Retrieve the current value */
	local color							= MathHelper.ValidateColor( ctrl.BackgroundFader:GetCurrentValue() )
	
	/* Debug output */
	if not color then
		DEBUG:ErrMsg( "Invalid backcolor", "BelButton.GetCurrentBackcolor" )
	end
	
	/* Extract the color */
	local ret							= color
	if not IsColor( color ) then ret	= Color( color[1], color[2], color[3], color[4] ) end
	
	/* Update alpha */
	color.a								= math.min( color.a, ctrl.ShowHideFader:GetCurrentValue().Alpha )
	
	/* Return the color */
	return ret
end

/* Cursor enters: Out -> In */
BelControls.OnCursorEntered				= function( ctrl )
	
	/* Call base */
	if ctrl.DermaType.OnCursorEntered then
		ctrl.DermaType.OnCursorEntered( ctrl )
	end
	
	ctrl.CurrentControlState = CTRL_STATE_IN
	ctrl.BackgroundFader.Animation.Keyframes[2]:SetStoppable()
	ctrl.BackgroundFader:FadeIn()
end

/* Cursor leaves: In -> Out */
BelControls.OnCursorExited				= function( ctrl )
	
	/* Call base */
	if ctrl.DermaType.OnCursorExited then
		ctrl.DermaType.OnCursorExited( ctrl )
	end

	ctrl.CurrentControlState = CRL_STATE_OUT
	ctrl.BackgroundFader.Animation.Keyframes[2]:SetContinuous()
	ctrl.BackgroundFader:FadeOut()
end

/* Mouse pressed: In -> Down */
BelControls.OnMousePressed				= function( ctrl )

	/* Call base */
	if ctrl.DermaType.OnMousePressed then
		ctrl.DermaType.OnMousePressed( ctrl )
	end
	
	ctrl.CurrentControlState = CTRL_STATE_DOWN
	ctrl.BackgroundFader.Animation.Keyframes[2]:SetContinuous()
	ctrl.BackgroundFader:FadeIn()
end

/* Mouse released: Down -> In */
BelControls.OnMouseReleased				= function( ctrl )

	/* Call base */
	if ctrl.DermaType.OnMouseReleased then
		ctrl.DermaType.OnMouseReleased( ctrl )
	end
	
	ctrl.CurrentControlState = CTRL_STATE_IN
	ctrl.BackgroundFader.Animation.Keyframes[2]:SetStoppable()
	ctrl.BackgroundFader:FadeOut()
end

/* Remove the button and its resources */
BelControls.Dispose						= function( ctrl )

	/* If control is not registered, nothing can be done */
	if not ctrl.IsRegistered then
		DEBUG:ErrMsg( "The control needs to be registered. Call 'BelControls.Register' first.", "BelControls.Dispose" )
		return false
	end
	
	/* Variables */
	local ok							= true
	
	/* Debug output */
	 if zed then zed = zed end -- DEBUG:Msg( "Removing control resources.", "BelControls.Dispose" )
	
	/* Delete resources (timers and such) */
	ctrl.BackgroundFader:Dispose()
	ctrl.ShowHideFader:Dispose()
	
	/* Call on children */
	for k,v in pairs( ctrl.Children ) do
		ok = ( ok and v:Dispose() )
	end
	
	/* Return the result */
	return ok
end

/*****************************************************************************************/
/**	DESIGN																				**/
/*****************************************************************************************/

/* Paint the control */
BelControls.Paint						= function( ctrl )
	
	/* Wait until we're ready */
	if not ctrl.IsRegistered then return end
	
	/* Get current backcolor */
	local bgColor						= ctrl:GetCurrentBackcolor()
	
	/* Draw with that color */
	ctrl:Draw( bgColor )
end

/* Draw the control */
BelControls.Draw						= function( ctrl, color )

	/* Wait until we're ready */
	if not ctrl.IsRegistered then return end

	/* Variables */
	local w								= ctrl:GetWide()
	local h								= ctrl:GetTall()
	local mw							= ctrl:GetMaxWide()
	local mh							= ctrl:GetMaxTall()
	local s								= math.max( w, h )
	local x								= ( mw * ctrl.Origin.x ) - ( w * ctrl.Origin.x )
	local y								= ( mh * ctrl.Origin.y ) - ( h * ctrl.Origin.y )
	local cornerSize					= ( ctrl.CornerSizeRatio * s ) - ( ( ctrl.CornerSizeRatio * s ) % 4 )
	local fc							= ctrl:GetTextColor()
	local foreColor
	
	/* Update the alpha channel of the text color */
	foreColor = Color( fc.r, fc.g, fc.b, color.a )
	ctrl:SetTextColor( foreColor )
	ctrl:SetTextColorHovered( MathHelper.ClampColor( Color( fc.r, fc.g, fc.b, color.a + 50 ) ) )
	
	/* Don't draw anything if the alpha is equal to 0 */
	if color.a == 0 then return end
	
	/* Take shadow into account */
	if ctrl.DropShadow then
	
		/* Size must be slighly smaller for the shadow to be fully integrated */
		w								= w - 3
		h								= h - 3
		
		/* Draw the shadow first */
		local sColor					= Color( ctrl.ShadowColor.r, ctrl.ShadowColor.g, ctrl.ShadowColor.b, math.min( ctrl.ShadowColor.a, color.a ) )
		draw.RoundedBox( cornerSize, 3, 3, w, h, sColor )
	end
	
	/* Single color */
	if not ctrl.SplitDesign then
		draw.RoundedBox( cornerSize, 0, 0, w, h, color )
		
	/* Two colors */
	else
		draw.RoundedBoxEx(
			cornerSize, 0, 0, w, h / 2, color,
			true, true, false, false)
		draw.RoundedBoxEx(
			cornerSize, 0, 0 + h / 2, w, h / 2, MathHelper.ClampColor( Color( color.r - 15, color.g - 15, color.b - 15, color.a + 15 ) ),
			false, false, true, true)
	end
	
	/* Need a border ? */
	if ctrl.IncrustBorder then
	
		/* White */
		surface.SetDrawColor( 255, 255, 255, color.a )
		surface.DrawOutlinedRect( 0 + 5, 0 + 5, w - 10, h - 10 )
		if ctrl.CurrentControlState == CTRL_STATE_DOWN then
			surface.DrawOutlinedRect( 0 + 6, 0 + 6, w - 12, h - 12 )
		end
		
		/* Black */
		surface.SetDrawColor( 0, 0, 0, color.a )
		surface.DrawOutlinedRect( 0 + 4, 0 + 4, w - 10, h - 10 )
		if ctrl.CurrentControlState == CTRL_STATE_DOWN then
			surface.DrawOutlinedRect( 0 + 5, 0 + 5, w - 12, h - 12 )
		end
	end
end

/*****************************************************************************************/
/**	EVENTS																				**/
/*****************************************************************************************/

/* Every tick of the background fader */
BelControls.BackgroundFaderTick			= function( fader )
	
end

/* Every tick of the show / hide fader */
BelControls.ShowHideFaderTick			= function( fader )
	
	/* Update control size */
	local ctrl							= fader.LinkedObject
	local val							= fader:GetCurrentValue()
	
	/* Update control if it is valid */
	if IsPanel( ctrl ) and IsValid( ctrl ) then
	
		/* If dragging, set the current pos as the new final pos */
		if ctrl.CurrentControlState == CTRL_STATE_DOWN then
			local px,py							= ctrl:GetPos()
			ctrl:SetFinalPos( px, py )
		end
		
		/* Update size and pos */
		local fPos						= ctrl:GetFinalPos()
		local o							= ctrl.Origin
		local mw						= ctrl:GetMaxWide()
		local mh						= ctrl:GetMaxTall()
		ctrl:SetSize( val.Width, val.Height )
		ctrl:SetPos(
			fPos.x + ( mw * o.x ) - ( val.Width * o.x ),
			fPos.y + ( mh * o.y ) - ( val.Height * o.y )
		)
	end
end

/* Called when the background fader has reached start or end */
BelControls.BackgroundFadeComplete		= function( fader )
	
	/* Retrieve the control */
	local ctrl							= fader.LinkedObject
end

/* Called when the show / hide fader has reached start or end */
BelControls.ShowHideFadeComplete		= function( fader )
	
	/* Retrieve the control */
	local ctrl							= fader.LinkedObject
	
	/* Stop the fader */
	fader:Dispose()
	
	/* Debug output */
	if fader.Direction == FADE_DIRECTION_IN then
		 if zed then zed = zed end -- DEBUG:Msg( "Control shown", "BelControls.ShowHideFadeComplete" )
	else
		 if zed then zed = zed end -- DEBUG:Msg( "Control hidden", "BelControls.ShowHideFadeComplete" )
	end
	
	/* Do nothing else if the control is not a registered BelControl */
	if not IsPanel( ctrl ) or not ctrl.IsRegistered then
		 if zed then zed = zed end -- DEBUG:Msg( "A non-registered BelControl was shown / hidden", "BelControls.ShowHideFadeComplete" )
		return
	end
	
	/* In case of a fade in */
	if fader.Direction == FADE_DIRECTION_IN then
		
		/* If control has no children then raise OnShown */
		if not IsTable( ctrl.Children ) or table.Count( ctrl.Children ) == 0 or not ctrl.WaitForChildren then
			 if zed then zed = zed end -- DEBUG:Msg( "No children, notify showing complete.", "BelControls.ShowHideFadeComplete" )
			if ctrl.OnShown then
				 if zed then zed = zed end -- DEBUG:Msg( "Sent notification to function " .. tostring( ctrl.OnShown ), "BelControls.ShowHideFadeComplete" )
				ctrl:OnShown( ctrl )
			end
			
		/* Otherwise start showing the first child */
		else
			 if zed then zed = zed end -- DEBUG:Msg( "Control has " .. table.Count( ctrl.Children ) .. " children. Showing them....", "BelControls.ShowHideFadeComplete" )
			ctrl.Children[1]:SetVisible( true )
		end
	
	/* In case of a fade out */
	elseif fader.Direction == FADE_DIRECTION_OUT then
		
		/* Notify the parent that a child was hidden */
		if ctrl.OnHidden then
			 if zed then zed = zed end -- DEBUG:Msg( "Notifying parent of child hidden.", "BelControls.ShowHideFadeComplete" )
			ctrl:OnHidden( ctrl )
		end
		
	/* ???	*/	
	else
		DEBUG:ErrMsg( "Unknown direction: " .. tostring( fader.Direction ), "BelControls.ShowHideFadeComplete" )
	end
end

/* When a child control is fully visible */
BelControls.ChildShown					= function( child )
	
	/* Get the parent */
	local parent						= child:GetParent()
	
	/* Debug output */
	 if zed then zed = zed end -- DEBUG:Msg( "Child control shown", "BelControls.ChildShown" )
	
	/* Ensure it is a BelControl */
	if not parent.IsRegistered then
		DEBUG:ErrMsg( "Parent control is not a BelControl or is not registered as one.", "BelControls.ChildShown" )
		return
	end
	
	/* Do nothing else if we shouldn't wait for children */
	if not parent.WaitForChildren then return end
	
	/* Find the child in children list */
	local i								= -1
	for k,v in ipairs( parent.Children ) do
		if child == v then
			i							= k
			break
		end
	end
	
	/* If not found, raise an error */
	if i == -1 then
		DEBUG:ErrMsg( "The child was not found.", "BelControls.ChildShown" )
		return
	end
	
	/* If it was the last child then raise OnShown */
	local count							= table.Count( parent.Children )
	if i == count then
		 if zed then zed = zed end -- DEBUG:Msg( "Last child was shown, notifying showing complete.", "BelControls.ChildShown" )
		if parent.OnShown then
			 if zed then zed = zed end -- DEBUG:Msg( "Sent notification.", "BelControls.ChildShown" )
			parent:OnShown( parent )
		end
		
	/* Otherwise start showing the next child */
	else
		local nextChild					= parent.Children[i + 1]
		if IsPanel( nextChild ) and nextChild.IsRegistered then
			 if zed then zed = zed end -- DEBUG:Msg( "Showing next child.", "BelControls.ChildShown" )
			nextChild:SetVisible( true )
		else
			 if zed then zed = zed end -- DEBUG:Msg( "Next child is invalid.", "BelControls.ChildShown" )
		end
	end
end

/* When a child control is fully hidden */
BelControls.ChildHidden					= function( child )

	/* Get the parent */
	local parent						= child:GetParent()
	
	/* Debug output */
	 if zed then zed = zed end -- DEBUG:Msg( "Child control hidden", "BelControls.ChildHidden" )
	
	/* Ensure it is a BelControl */
	if not parent.IsRegistered then
		DEBUG:ErrMsg( "Parent control is not a BelControl or is not registered as one.", "BelControls.ChildHidden" )
		return
	end
	
	/* Do nothing else if we shouldn't wait for children */
	if not parent.WaitForChildren then return end
	
	/* Find the child in children list */
	local i								= -1
	for k,v in ipairs( parent.Children ) do
		if child == v then
			i							= k
			break
		end
	end
	
	/* If not found, raise an error */
	if i == -1 then
		DEBUG:ErrMsg( "The child was not found.", "BelControls.ChildHidden" )
		return
	end
	
	/* If it was the first child then hide the parent */
	if i == 1 then
		parent.ShowHideFader:FadeOut()
		-- if parent.OnHidden then
			-- parent:OnHidden( parent )
		-- end
		
	/* Otherwise start hiding the previous child */
	else
		local prevChild					= parent.Children[i - 1]
		if IsPanel( prevChild ) and prevChild.IsRegistered then
			prevChild:SetVisible( false )
		end
	end
end

/*****************************************************************************************/
/**	META DATA																			**/
/*****************************************************************************************/

/* Hooks table */
BelControls.Hooks = {
	["is_a"]							= {},
	["GetCurrentBackcolor"]				= {},
	["GetFinalPos"]						= {},
	["SetFinalPos"]						= {},
	["GetTextColor"]					= {},
	["SetTextColor"]					= {},
	["GetTextColorHovered"]				= {},
	["SetTextColorHovered"]				= {},
	["SetMaxWide"]						= {},
	["SetMaxTall"]						= {},
	["GetMaxWide"]						= {},
	["GetMaxTall"]						= {},
	["GetMaxAlpha"]						= {},
	["SetMaxAlpha"]						= {},
	["IsVisible"]						= {},
	["SetVisible"]						= {},
	["OnCursorEntered"]					= {},
	["OnCursorExited"]					= {},
	["OnMousePressed"]					= {},
	["OnMouseReleased"]					= {},
	["Paint"]							= {},
	["Draw"]							= {},
	["Dispose"]							= {},
	["OnShown"]							= {},
	["OnHidden"]						= {},
	["ChildShown"]						= {},
	["ChildHidden"]						= {}
}

/* Hook calls */
BelControls.Call						= function( src, fct, ... )
	local result = {}
	for k,v in pairs( BelControls.Hooks[fct] ) do
		if k == src then
			for i,f in ipairs( v ) do
				local r = f( src, ... )
				if r then
					table.insert( result, r )
				end
			end
		end
	end
	if table.Count( result ) == 1 then
		return result[1]
	elseif table.Count( result ) > 1 then
		return result
	else
		return nil
	end
end

/* Add a hook */
BelControls.AddHook						= function( fct, ctrl, hdl )

	/* If control is not registered, nothing can be done */
	if not ctrl.IsRegistered then
		DEBUG:ErrMsg( "'" .. fct .. "' hook couldn't be added because the control is not registered. Call 'BelControls.Register' first.", "BelControls.AddHook" )
		return false
	end
	
	/* Add the hook */
	table.insert( BelControls.Hooks[fct][ctrl], hdl )
	
	/* Debug output */
	 if zed then zed = zed end -- DEBUG:Msg( "Successfully hooked '" .. fct .. "' to handler " .. tostring( hdl ), "BelControls.AddHook" )
	
	/* Return true if the hook could be added */
	return true
end

/* Remove a hook */
BelControls.RemoveHook					= function( fct, ctrl, hdl )

	/* If control is not registered, it won't have hooks */
	if not ctrl.IsRegistered then
		 if zed then zed = zed end -- DEBUG:Msg( "The control is not registered and thus cannot have hooks. Call 'BelControls.Register' first.", "BelControls.RemoveHook" )
		return false
	end

	/* Loop control hooks */
	for k,v in pairs( BelControls.Hooks[fct] ) do
		if k == ctrl then
			for i,f in ipairs( v ) do
				if f == hdl then
					table.remove( v, f )
					return true
				end
			end
		end
	end
	
	/* Handler not found */
	return false
end

/* Clear the hooks */
BelControls.ClearHooks					= function( fct, ctrl )

	/* If control is not registered, it won't have hooks */
	if not ctrl.IsRegistered then
		 if zed then zed = zed end -- DEBUG:Msg( "The control is not registered and thus cannot have hooks. Call 'BelControls.Register' first.", "BelControls.ClearHooks" )
		return false
	end
	
	/* Loop control hooks */
	if not BelControls.Hooks[fct] then
		BelControls.Hooks[fct] = {}
	end
	BelControls.Hooks[fct][ctrl]		= {}
end